/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bgu.ppm.dat.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.util.EventObject;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JTree;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;

/**
 *
 * @author User
 */
public class TreeCheckBoxRenderer extends javax.swing.JPanel implements TreeCellRenderer, TreeCellEditor {

    public static final Color SELECTION_COLOR = new Color(151, 214, 255);
    private final List<CellEditorListener> listeners = new LinkedList<>();
    private SelecteableItem item;
    private Object value;
    private boolean editingTextAllowed = true;
    private boolean editingText = false;
    private JTree tree;

    /**
     * Creates new form TreeCheckBoxRenderer
     */
    public TreeCheckBoxRenderer() {
        initComponents();
    }

    public void setEditingTextAllowed(boolean editingTextAllowed) {
        this.editingTextAllowed = editingTextAllowed;
    }

    public boolean isEditingTextAllowed() {
        return editingTextAllowed;
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        text = new javax.swing.JTextField();
        box = new javax.swing.JCheckBox();
        lbl = new javax.swing.JLabel();

        text.setText("jTextField1");
        text.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                textActionPerformed(evt);
            }
        });
        text.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusLost(java.awt.event.FocusEvent evt) {
                textFocusLost(evt);
            }
        });

        setLayout(new java.awt.BorderLayout());

        box.setBackground(new java.awt.Color(151, 214, 255));
        box.setOpaque(false);
        box.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                boxMouseClicked(evt);
            }
        });
        box.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                boxActionPerformed(evt);
            }
        });
        box.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                boxKeyPressed(evt);
            }
        });
        add(box, java.awt.BorderLayout.LINE_START);

        lbl.setText("jLabel1");
        lbl.setPreferredSize(new java.awt.Dimension(34, 16));
        add(lbl, java.awt.BorderLayout.CENTER);
    }// </editor-fold>//GEN-END:initComponents

    private void boxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_boxActionPerformed
        if (item != null) {
            item.setSelected(box.isSelected());
        }
    }//GEN-LAST:event_boxActionPerformed

    private void boxMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_boxMouseClicked
        if (evt.getClickCount() == 2 && editingTextAllowed && item != null && item.isCanEditText()) {
            switchToTextEditing();
        }
    }//GEN-LAST:event_boxMouseClicked

    private void boxKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_boxKeyPressed
        switch (evt.getKeyCode()) {
            case KeyEvent.VK_DOWN:
            case KeyEvent.VK_UP:
                for (CellEditorListener l : listeners) {
                    l.editingStopped(new ChangeEvent(value));
                }
                tree.dispatchEvent(evt);
                break;
            case KeyEvent.VK_ENTER:
                System.out.println("Enter on item: " + item);
                if (editingTextAllowed && item != null && item.isCanEditText()) {
                    switchToTextEditing();
                }
                break;
        }
    }//GEN-LAST:event_boxKeyPressed

    private void textActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_textActionPerformed
        applyTextEditing();
    }//GEN-LAST:event_textActionPerformed

    private void textFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_textFocusLost
    }//GEN-LAST:event_textFocusLost
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JCheckBox box;
    private javax.swing.JLabel lbl;
    private javax.swing.JTextField text;
    // End of variables declaration//GEN-END:variables

    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
        if (hasFocus) {
            setBackground(SELECTION_COLOR);
        } else {
            setBackground(tree.getBackground());
        }

        this.tree = tree;
        this.value = value;
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
        item = (SelecteableItem) node.getUserObject();
        
        //editingText = editingText && item.isCanEditText();
        if (editingText) {
            switchToTextEditing();
        } else {
            switchToBoxEditing();
        }

        requestFocus();

        return this;
    }

    @Override
    public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {
        getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, leaf);
        setBackground(SELECTION_COLOR);
        return this;
    }

    @Override
    public Dimension getPreferredSize() {
        Dimension d = new Dimension(24 + lbl.getMaximumSize().width, 18);
        return d;
    }

    @Override
    public Object getCellEditorValue() {
        return item;
    }

    @Override
    public boolean isCellEditable(EventObject anEvent) {
        editingText = anEvent == null && editingTextAllowed && item != null && item.isCanEditText();
        return true;
    }

    @Override
    public boolean shouldSelectCell(EventObject anEvent) {
        return true;
    }

    @Override
    public boolean stopCellEditing() {
        item = null;
        return true;
    }

    @Override
    public void cancelCellEditing() {
        if (editingText && item != null && item.isCanEditText()) {
            applyTextEditing();
        }
        item = null;
    }

    @Override
    public void addCellEditorListener(CellEditorListener l) {
        listeners.add(l);
    }

    @Override
    public void removeCellEditorListener(CellEditorListener l) {
        listeners.remove(l);
    }

    private void switchToBoxEditing() {
        editingText = false;

        removeAll();
        add(box, BorderLayout.WEST);
        add(lbl, BorderLayout.CENTER);
        lbl.setText("" + item);
        box.setSelected(item.isSelected());
    }

    private void switchToTextEditing() {
        if (item != null && item.isCanEditText()) {
            editingText = true;

            removeAll();
            add(text, BorderLayout.CENTER);
            text.setText("" + item);

            text.requestFocus();
            text.setSelectionStart(0);
            text.setSelectionEnd(text.getText().length());

            invalidate();
            validate();
            repaint();
        }
    }

    private void applyTextEditing() {
        if (item != null && item.isCanEditText()) {
            item.setFromText(text.getText());
            switchToBoxEditing();

            for (CellEditorListener l : listeners) {
                l.editingStopped(new ChangeEvent(item));
            }
        }
    }
}
